﻿/*
 * Copyright © 2020, Wuxi Safover Intelligent Technology Co., Ltd. All rights reserved.
 * 
 * 无锡安永智能科技有限公司版权所有，未经许可，不得用于商业用途
 * 
 * Visit: https://www.safover.com/ 
 */

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Safover.LidarCollector.Core;

namespace Ac.Bly
{
    public class VirtualBlyAcquisitionCard : AcquisitionCard
    {
        #region Singleton
        public static VirtualBlyAcquisitionCard Instance { get; } = new VirtualBlyAcquisitionCard();

        private VirtualBlyAcquisitionCard() { }
        #endregion

        private bool IsVirtualDeviceConnected { get; set; }

        private string Name => "VirtualBlyAcquisitionCard";

        public override bool IsConnected => IsVirtualDeviceConnected;

        public override bool Disconnect()
        {
            if (!IsVirtualDeviceConnected)
            {
                throw new InvalidOperationException($"{Name} is already connected.");
            }

            IsVirtualDeviceConnected = false;

            StopAcquisition();

            AcquisitionCardStatusChanged?.Invoke(this, new AcquisitionCardStatusChangedEventArgs(false, "主动断开服务"));

            return true;
        }

        public override void KeepConnection()
        {
            IsVirtualDeviceConnected = true;

            AcquisitionCardStatusChanged?.Invoke(this, new AcquisitionCardStatusChangedEventArgs(true, "服务连接成功"));
        }

        public override bool InitParams(int channelId, int samplingDepth, int cumulativePulses)
        {
            Debug.WriteLine($"{Name}: reset params, samplingDepth=[{samplingDepth}], cumulativePulses=[{cumulativePulses}].");
            return true;
        }

        private Thread CollectorThread { get; set; }
        private bool ShouldContinue { get; set; }
        private bool IsCollectorThreadWorking { get; set; }

        public override bool StartAcquisition()
        {
            if (IsCollectorThreadWorking) return true;

            CollectorThread = new Thread(CollectionLoop)
            {
                Name = $"{Name}_Thread",
            };
            ShouldContinue = true;
            CollectorThread.Start();

            return true;
        }

        private void CollectionLoop()
        {
            if (IsCollectorThreadWorking) return;

            IsCollectorThreadWorking = true;

            var lines = new List<string>(File.ReadAllLines(@"C:\Work\Radar\BlyAcTestRawData1.txt"));

            try
            {
                int index = 0;
                while (ShouldContinue)
                {
                    Thread.Sleep(2000);

                    var line = lines[index];
                    var bytes = BuildVirtualPacket(line);

                    var packetLength = BitConverter.ToUInt16(bytes, 9);

                    var cumulativePulses = BitConverter.ToUInt16(bytes, 15);
                    var samplingDepth = BitConverter.ToUInt16(bytes, 17);
                    var channelNumber = bytes[21];

                    var values = new List<double>();

                    var x = bytes[15] + (bytes[16] >> 8);
                    for (int offset = 22; offset < packetLength - 1; offset += 4)
                    {
                        var v = (bytes[offset] + (bytes[offset + 1] >> 8) + (bytes[offset + 2] >> 16) + (bytes[offset + 3] >> 24)) / x;
                        v = 10000 * (v - 32768) / 65536;

                        values.Add(v);
                    }

                    index = ++index % lines.Count;

                    OnLidarDataRecieved(this, new LidarDataReceivedEventArgs
                    {
                        ChannelNumber = channelNumber,
                        CumulativePulses = cumulativePulses,
                        SamplingDepth = samplingDepth,
                        Values = values.ToArray()
                    });
                }
            }
            finally
            {
                IsCollectorThreadWorking = false;
            }
        }

        public override bool StopAcquisition()
        {
            if (!IsCollectorThreadWorking) return false;

            ShouldContinue = false;

            CollectorThread.Abort(); //;.Join();

            return true;
        }

        private byte[] BuildVirtualPacket(string raw)
        {
            var segments = raw.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            var bytes = new List<byte>();

            foreach (var segment in segments)
            {
                bytes.Add(byte.Parse(segment, System.Globalization.NumberStyles.AllowHexSpecifier));
            }

            return bytes.ToArray();
        }

        public override bool Reset()
        {
            Debug.WriteLine($"{Name}: Clear data done.");

            return true;
        }
    }
}
